# SageTV objects

import os, threading, xbmc, xbmcgui, time, datetime
import urllib, urllib2, re, copy, xml.dom.minidom
import copy, urllib
from string import split, replace, find
from xml.dom import Node

try: Emulating = xbmcgui.Emulating
except: Emulating = False
dialog = xbmcgui.Dialog()

#Declare global static variables
ACTION_MOVE_LEFT        = 1
ACTION_MOVE_RIGHT       = 2
ACTION_MOVE_UP          = 3
ACTION_MOVE_DOWN        = 4
ACTION_PAGE_UP          = 5
ACTION_PAGE_DOWN        = 6
ACTION_SELECT_ITEM      = 7
ACTION_HIGHLIGHT_ITEM   = 8
ACTION_PARENT_DIR       = 9
ACTION_PREVIOUS_MENU    = 10
ACTION_SHOW_INFO        = 11
ACTION_PAUSE            = 12
ACTION_STOP             = 13
ACTION_NEXT_ITEM        = 14
ACTION_PREV_ITEM        = 15
ACTION_SCROLL_UP        = 111
ACTION_SCROLL_DOWN      = 112
ACTION_REMOTE_PLAY      = 79
ACTION_REMOTE_BACK      = 9
SORTBYDATEDESC          = 0
SORTBYDATEASC           = 1
SORTBYTITLE             = 2

# function to limit the need for repetitive entries in the main program
# and allow for sitewide changes from one place.
def button(x,y,w,h):
    return xbmcgui.ControlButton(
        x              = settings.scw(x+settings.x),
        y              = settings.sch(y+settings.y),
        width          = settings.scw(w),
        height         = settings.sch(h),
        label          = '',
        textColor      = settings.colorText,
        focusedColor   = settings.colorBold,
        focusTexture   = settings.imgMenuFocus,
        noFocusTexture = settings.imgMenuNoFocus )

# function to limit the need for repetitive entries in the main program
# and allow for sitewide changes from one place.
def label(x,y,w,h):
    return xbmcgui.ControlLabel(
        x              = settings.scw(x+settings.x),
        y              = settings.sch(y+settings.y),
        width          = settings.scw(w),
        height         = settings.sch(h),
        label          = '',
        textColor      = settings.colorText )

# function to limit the need for repetitive entries in the main program
# and allow for sitewide changes from one place.
def flabel(x,y,w,h):
    return xbmcgui.ControlFadeLabel(
        x              = settings.scw(x+settings.x),
        y              = settings.sch(y+settings.y),
        width          = settings.scw(w),
        height         = settings.sch(h),
        textColor      = settings.colorText )

# function to limit the need for repetitive entries in the main program
# and allow for sitewide changes from one place.
def clist(x,y,w,h):
    return xbmcgui.ControlList(
        x                  = settings.scw(x+settings.x),
        y                  = settings.sch(y+settings.y),
        width              = settings.scw(w),
        height             = settings.sch(h),
        textColor          = settings.colorText,
        buttonTexture      = settings.imgMenuNoFocus,
        buttonFocusTexture = settings.imgMenuFocus,
        selectedColor      = settings.colorBold)

# function to limit the need for repetitive entries in the main program
# and allow for sitewide changes from one place.
def image(x,y,w,h,img):
    return xbmcgui.ControlImage(
        x        = settings.scw(x+settings.x),
        y        = settings.sch(y+settings.y),
        width    = settings.scw(w),
        height   = settings.sch(h),
        filename = img )

class Settings:
    def __init__(self):
        self.ipaddress        = "0.0.0.0"
        self.port             = "8080"
        self.userid           = "Sage"
        self.password         = "Sage"
        self.dirSkin          = "skins\\BlueTwoDark\\"
        self.RecordingPath    = []
        self.XBMCPath         = []
        self.Resolution       = 4
        self.x                = 30
        self.y                = -15
        self.ShowEpisodeNames = False
        self.ShowDontLike     = False
        self.ShowArchive      = False
        self.AutoRefresh      = False
        self.colorText        = "0xFFCCCCCC"
        self.colorBold        = "0xFFFFFFFF"
        self.colorDisabled    = "0xFFFF3300"
        self.screenWidth      = 720
        self.screenHeight     = 480
        self.scaleWidth       = 1.0
        self.scaleHeight      = 1.0

    def scw(self, value):
        result = int(self.scaleWidth*value)
        return result

    def sch(self, value):
        result = int(self.scaleHeight*value)
        return result

    def grab(self, tagname, attribname):
        value = ""
        try:
            XMLFile = open(dirHome + 'settings.xml', "rU")
            XMLData = XMLFile.read()
            dom = xml.dom.minidom.parseString(XMLData)
            XMLFile.close()
            Item = dom.getElementsByTagName(tagname)[0]
            self.tagname = tagname
            self.attribname = attribname
            value = str(Item.getAttribute(attribname))
        except:
            value = ""
        return value

    def grabColor(self, tagname, attribname):
        value = ""
        try:
            XMLFile = open(dirHome + self.dirSkin + 'colors.xml', "rU")
            XMLData = XMLFile.read()
            dom = xml.dom.minidom.parseString(XMLData)
            XMLFile.close()
            Item = dom.getElementsByTagName(tagname)[0]
            self.tagname = tagname
            self.attribname = attribname
            value = str(Item.getAttribute(attribname))
        except:
            value = "0xFFFFFFFF"
        return value

    def populate(self):
        dirList = os.listdir(dirHome)
        found = False
        for i in range(len(dirList)):
            if dirList[i] == "settings.xml":
                found = True
        if not found:
            newfile = open(dirHome + "settings.xml",'w')
            newfile.close()
        self.ipaddress     = self.grab("Connection", "Ipaddress")
        if self.ipaddress == "":
            self.ipaddress     = "0.0.0.0"
        else:
            self.port          = self.grab("Connection", "Port")
            self.userid        = self.grab("Connection", "UserId")
            self.password      = self.grab("Connection", "Password")
            self.dirSkin       = "skins\\" + self.grab("Appearance", "Skin") + "\\"
            self.RecordingPath = self.grab("System", "RecordingPath").split(',')
            self.XBMCPath      = self.grab("System", "XBMCPath").split(',')
            if self.grab("Graphics", "Resolution") != "":
                self.Resolution    = int(self.grab("Graphics", "Resolution"))
            if self.grab("Graphics", "xoffset") != "":
                self.x             = int(self.grab("Graphics", "xoffset"))
            if self.grab("Graphics", "yoffset") != "":
                self.y             = int(self.grab("Graphics", "yoffset"))
            if self.grab("Appearance", "ShowEpisodeNames").lower() == "true": self.ShowEpisodeNames = True
            else: self.ShowEpisodeNames = False
            if self.grab("Appearance", "ShowDontLike").lower()     == "true": self.ShowDontLike     = True
            else: self.ShowDontLike = False
            if self.grab("Appearance", "ShowArchive").lower()      == "true": self.ShowArchive      = True
            else: self.ShowArchive = False
            if self.grab("Appearance", "AutoRefresh").lower()      == "true": self.AutoRefresh      = True
            else: self.AutoRefresh = False
            # Update the images
            self.imgBackground    = dirHome + self.dirSkin + "background" + str(self.Resolution) + ".png"
            self.imgMenuFocus     = dirHome + self.dirSkin + 'list_sub_focus.png'
            self.imgMenuNoFocus   = dirHome + self.dirSkin + 'list_sub_nofocus.png'
            self.imgTVLogo        = dirHome + self.dirSkin + 'television_logo.png'
            self.imgRecording     = dirHome + self.dirSkin + 'MarkerRecording.png'
            self.imgWatched       = dirHome + self.dirSkin + 'MarkerWatched.png'
            self.imgArchived      = dirHome + self.dirSkin + 'MarkerArchived.png'
            self.imgDontLike      = dirHome + self.dirSkin + 'MarkerDontLike.png'
            self.imgArrowRightNF  = dirHome + self.dirSkin + 'arrow_round_right_nofocus.png'
            self.imgLock          = dirHome + self.dirSkin + 'lock.png'
            self.imgCurRec        = dirHome + self.dirSkin + 'cur_rec.png'
            self.imgSeriesRec     = dirHome + self.dirSkin + 'series_rec.png'
            self.imgManualRec     = dirHome + self.dirSkin + 'man_rec.png'
            self.imgWatchedS      = dirHome + self.dirSkin + 'watched.png'
            self.imgDontLikeS     = dirHome + self.dirSkin + 'dontlike.png'
            self.imgRating        = dirHome + settings.dirSkin + 'Rating_'
            # Get the font colors
            self.colorText     = self.grabColor("font", "normal")
            self.colorBold     = self.grabColor("font", "bold")
            self.colorDisabled = self.grabColor("font", "disabled")
            # Set up the proper width and height for the resolution
            if self.Resolution == 0:
                self.screenWidth  = 1920
                self.screenHeight = 1080
            elif self.Resolution == 1:
                self.screenWidth  = 1200
                self.screenHeight = 720
            elif self.Resolution == 6 or self.Resolution == 7:
                self.screenWidth  = 720
                self.screenHeight = 576
            else:
                self.screenWidth  = 720
                self.screenHeight = 480
            # Now set the scaling properly
            self.scaleWidth  = self.screenWidth/720.0
            self.scaleHeight = self.screenHeight/480.0
            # Give a warning if paths don't match up
            if len(self.RecordingPath) != len(self.XBMCPath):
                dialog.ok("Warning", "You have a different number of RecordingPaths and XBMCPaths in settings.xml.  This could lead to incorrect behavior")

    def update(self, tag, attr, value):
        try:
            XMLFile = open(dirHome + 'settings.xml', "r")
            XMLData = XMLFile.read()
            dom = xml.dom.minidom.parseString(XMLData)
            XMLFile.close()
            Item = dom.getElementsByTagName(tag)[0]
            Item.setAttribute(attr, value)
            xmlstring = dom.toxml(encoding="utf-8")
            f = file(dirHome + 'settings.xml', 'wb')
            try:
                f.write(xmlstring)
            finally:
                f.close()
        except:
            dialog.ok("SageTV", "Cannot write to " + dirHome + "settings.xml")


# Global Variables that need to be set by calling script
dirHome          = ""
webaddress       = ""
offset           = ""
CURRENT_DATE     = ""
settings         = Settings()

def setDirhome(input):
    global dirHome
    dirHome = input
def setWebaddress(input):
    global webaddress
    webaddress = str(input)
def setOffset(input):
    global offset
    offset = input
def setCurrentDate(input):
    global CURRENT_DATE
    CURRENT_DATE = input
def setSettings(input):
    global settings
    settings = input

def NodeIterator(dom):
    # Print the node information in a dialog
    name  = dom.nodeName
    type  = dom.nodeType
    value = dom.nodeValue
    tname = ""
    if type == 1:  tname = "ELEMENT_NODE"
    if type == 2:  tname = "ATTRIBUTE_NODE"
    if type == 3:  tname = "TEXT_NODE"
    if type == 4:  tname = "CDATA_SECTION_NODE"
    if type == 5:  tname = "ENTITY_REFERENCE_NODE"
    if type == 6:  tname = "ENTITY_NODE"
    if type == 7:  tname = "PROCESSING_INSTRUCTION_NODE"
    if type == 8:  tname = "COMMENT_NODE"
    if type == 9:  tname = "DOCUMENT_NODE"
    if type == 10: tname = "DOCUMENT_TYPE_NODE"
    if type == 11: tname = "DOCUMENT_FRAGMENT_NODE"
    if type == 12: tname = "NOTATION_NODE"

    xmlstring = "Type:  " + str(tname) + "\n"
    xmlstring = xmlstring + "Name:  " + str(name) + "\n"
    xmlstring = xmlstring + "Value: " + str(value) + "\n"
    f = file(dirHome + 'debugDOM.txt', 'a')
    try:
        f.write(xmlstring)
    finally:
        f.close()

    try:
        nnm  = dom.attributes
        for i in range(nnm.length):
            NodeIterator(nnm.item(i))
    except: pass
    # If there are children call this same function recursively
    try:
        nodes = dom.childNodes
        for node in nodes:
            NodeIterator(node)
    except: pass

def WebXMLContent(content):
    XML = ""
    try:
        XML = xml.dom.minidom.parseString(content)
    except:
        dialog.ok("XML Parsing Error", "Could not parse:", content)
    return XML

def GetWebPage(URL):
    HTML = ""
    try:
        WebSock = urllib.urlopen(URL)  # Opens a 'Socket' to URL
        HTML    = WebSock.read()       # Reads Contents of URL and saves to Variable
        WebSock.close()                # Closes connection to url
    except:
        dialog.ok( "Connection Error", str(URL))
    HTML = HTML.decode("utf-8","replace")
    return HTML.encode("utf-8","replace")

def GetAsXML(URL):
    XML = ""
    try:
        WebSock = urllib.urlopen(URL)  # Opens a 'Socket' to URL
        HTML    = WebSock.read()       # Reads Contents of URL and saves to Variable
        WebSock.close()                # Closes connection to url
    except:
        dialog.ok( "Connection Error", str(URL))
    XML = HTML.decode("utf-8","replace")
    XML = XML.encode("utf-8","replace")
    XML = WebXMLContent( XML )
    return XML

class stream:
    def downloadURL(self, source, destination):
        try:
            loc = urllib.URLopener()
            loc.retrieve(source, destination)
        except:
            stream.message('Stream Failed: ' + str(source))

    def message(self, message):
        dialog = xbmcgui.Dialog()
        dialog.ok("SageTV", message)

class SingleParse:
    def parse(self, content, regex, clean):
        returnvar = ""
        list = re.compile( regex, re.I).findall(content)
        if len(list) == 0:
            # Nothing was found
            returnvar = ""
        elif len(list) ==1:
            returnvar = str(list[0])
        else:
            # For now we will just return the first instance, but we should probably do an error check
            returnvar = str(list[0])
            #returnvar = "MultiplesFound"
        if clean == 1:
            returnvar = returnvar.replace("&amp;", "&")
            returnvar = returnvar.replace("%60",   "'")
            returnvar = returnvar.replace("%27",   "'")
            returnvar = returnvar.replace("+",     " ")
        returnvar = returnvar.replace("%3A",   ":")
        return returnvar

class MultiParse:
    def parse(self, content, regex, clean):
        list = re.compile( regex, re.I).findall(content)
        if clean == 1:
            for i in range(len(list)):
                list[i] = list[i].replace("&amp;", "&")
                list[i] = list[i].replace("%60",   "'")
                list[i] = list[i].replace("%27",   "'")
                list[i] = list[i].replace("+",     " ")
                list[i] = list[i].replace("%3A",   ":")
                list[i] = str(list[i])
        return list

class DateConv:
    def toStringFromEpoch(self, epochSeconds):
        date = datetime.datetime.fromtimestamp(int(epochSeconds))
        return date.strftime("%m/%d/%Y %I:%M %p")

    def conv(self,datetext):
        date=""
        if datetext != "":
            year   = int(SingleParse().parse(datetext,'(\\d+)-\\d+-\\d+T\\d+:\\d+',0))
            month  = int(SingleParse().parse(datetext,'\\d+-(\\d+)-\\d+T\\d+:\\d+',0))
            day    = int(SingleParse().parse(datetext,'\\d+-\\d+-(\\d+)T\\d+:\\d+',0))
            hour   = int(SingleParse().parse(datetext,'\\d+-\\d+-\\d+T(\\d+):\\d+',0))
            minute = int(SingleParse().parse(datetext,'\\d+-\\d+-\\d+T\\d+:(\\d+)',0))
            date   = datetime.datetime(year,month,day,hour,minute)
            date   = date-offset
            date   = date.strftime("%m/%d/%Y %I:%M %p")
        return date
    def date(self,dateobj):
        date=dateobj.strftime("%m/%d/%Y")
        return date
    def time(self,dateobj):
        time=dateobj.strftime("%I:%M")
        if dateobj.strftime("%I") != dateobj.strftime("%H"): time = time + " PM"
        else: time = time + " AM"
        return time
    def object(self,datetext):
        date = ""
        if datetext != "":
            year   = int(SingleParse().parse(datetext,'(\\d+)-\\d+-\\d+T\\d+:\\d+',0))
            month  = int(SingleParse().parse(datetext,'\\d+-(\\d+)-\\d+T\\d+:\\d+',0))
            day    = int(SingleParse().parse(datetext,'\\d+-\\d+-(\\d+)T\\d+:\\d+',0))
            hour   = int(SingleParse().parse(datetext,'\\d+-\\d+-\\d+T(\\d+):\\d+',0))
            minute = int(SingleParse().parse(datetext,'\\d+-\\d+-\\d+T\\d+:(\\d+)',0))
            date   = datetime.datetime(year,month,day,hour,minute)
            date   = date-offset
        return date
    def stamp(self,datetext):
        date=0
        if datetext != "":
            year   = int(SingleParse().parse(datetext,'(\\d+)-\\d+-\\d+T\\d+:\\d+',0))
            month  = int(SingleParse().parse(datetext,'\\d+-(\\d+)-\\d+T\\d+:\\d+',0))
            day    = int(SingleParse().parse(datetext,'\\d+-\\d+-(\\d+)T\\d+:\\d+',0))
            hour   = int(SingleParse().parse(datetext,'\\d+-\\d+-\\d+T(\\d+):\\d+',0))
            minute = int(SingleParse().parse(datetext,'\\d+-\\d+-\\d+T\\d+:(\\d+)',0))
            date   = datetime.datetime(year,month,day,hour,minute)
            date   = date-offset
            date   = time.mktime(date.timetuple())
        return date

class Show:
    def __init__(self):
        self.epgId              = ""    # alphanumeric unique ID for the episode
        self.title              = ""    # alphanumeric
        self.episode            = ""    # alphanumeric
        self.duration           = 0     # numeric seconds
        self.category           = ""    # alphanumeric
        self.subCategory        = ""    # alphanumeric
        self.description        = ""    # alphanumeric
        self.rating             = ""    # alphanumeric
        self.advisoryList       = []    # Array of advisories (Just single strings)
        self.peopleList         = []    # Array of People
        self.year               = ""    # Alphanumeric
        self.language           = ""    # Alphanumeric
        self.originalAirDate    = ""    # Date
        self.startTime          = ""    # Not part of the original object
        self.timestamp          = ""    # Not part of the original object
        self.datestamp          = ""    # Not part of the original object
        self.duration           = 0     # Not part of the original object
        self.airings            = []    # Array of Airing
    def copy(self):
        return copy.copy(self)

class People:
    def __init__(self):
        self.role               = ""    # alphanumeric
        self.person             = ""    # alphanumeric

class Airing:
    def __init__(self):
        self.channedId          = ""    # Alpha since we will put in info instead of the ID
        self.favoriteId         = 0     # number cross reference to favorite
        self.duration           = 0     # number seconds
        self.sageDbId           = 0     # number unique airing ID for sage database
        self.startTime          = ""    # date
        self.parentalRating     = ""    # alphanumeric
        self.isHDTV             = False # Exists or not
        self.stereo             = False # Exists or not
        self.subtitled          = False # Exists or not
        self.closedCaptioned    = False # Exists or not
        self.sap                = False # Exists or not
        self.premierFinale      = ""    # Alphanumeric
        self.mediaFiles         = []    # Array of MediaFile

class MediaFile:
    def __init__(self):
        self.duration           = 0     # number seconds
        self.sageDbId           = 0     # number unique mediafile ID for sage database
        self.startTime          = ""    # date
        self.type               = ""    # alphanumeric
        self.archived           = False # Exists or not
        self.segments           = []    # array of Segments

class Segment:
    def __init__(self):
        self.duration           = 0     # number seconds
        self.filePath           = ""    # alphanumeric
        self.startTime          = ""    # date

class Channel:
    def __init__(self):
        self.channelId          = 0     # number (attribute)
        self.channelName        = ""    # alphanumeric
        self.channelDescription = ""    # alphanumeric
        self.channelNetwork     = ""    # alphanumeric
        self.channelNumber      = 0     # number

class Favorite:
    def __init__(self):
        self.favoriteId         = 0     # number (attribute)
        self.title              = ""    # alphanumeric
        self.channelName        = ""    # This gives the name to cross reference in the channel object
        self.timeslot           = ""    # Day HH24:MI
        self.firstRun           = False # Exists or not
        self.reRun              = False # Exists or not
        self.quality            = ""    # alphanumeric
        self.startPadding       = 0     # numeric seconds
        self.stopPadding        = 0     # numeric seconds
        self.keepAtMost         = 0     # number
        self.autoDelete         = False # Exists or not

class ParseIt:
    def nodes(self, dom, tag):
        nodeList = []
        for node in dom.getElementsByTagName(tag):
            if node.nodeName == tag:
                nodeList.append(copy.copy(node))
        return nodeList

    def value(self, node):
        return SingleParse().parse(str(node.toxml(encoding="utf-8")),'>(.*)<',1)

    def objectRef(self,dom):
        self.value = ""
        for node in dom.getElementsByTagName('objectRef'):
            self.value = node.getAttribute('ref')
        return self.value

    def genericValue(self,dom):
        self.value = ""
        for node in dom.getElementsByTagName('value'):
            if node.nodeName == 'value': self.value = ParseIt().value(node)
        return self.value

    def genericValues(self,dom):
        self.values   = []
        for nodelist in dom.getElementsByTagName('body'):
            for node in nodelist.childNodes:
                if node.nodeName == 'value': self.values.append(ParseIt().value(node))
        return self.values

    def channels(self,dom):
        self.channel   = []
        #Grab the channels
        for chan in dom.getElementsByTagName('channel'):
            newchan=Channel()
            newchan.channelId = chan.getAttribute('channelId')
            for node in chan.childNodes:
                if node.nodeName == 'channelName':        newchan.channelName        = ParseIt().value(node)
                if node.nodeName == 'channelDescription': newchan.channelDescription = ParseIt().value(node)
                if node.nodeName == 'channelNetwork':     newchan.channelNetwork     = ParseIt().value(node)
                if node.nodeName == 'channelNumber':      newchan.channelNumber      = ParseIt().value(node)
            if newchan.channelName != '':
                found = False
                for i in range(len(self.channel)):
                    if cmp(newchan.channelId,self.channel[i].channelId) == -1:
                        self.channel.insert(i, copy.copy(newchan))
                        found = True
                        break
                if not found:
                    self.channel.append(copy.copy(newchan))
        return self.channel

    def favorites(self,dom):
        self.favorite = []

        for fav in dom.getElementsByTagName('favorite'):
            newfav=Favorite()
            newfav.favoriteId = fav.getAttribute('favoriteId')
            for node in fav.childNodes:
                if node.nodeName == 'title':        newfav.title        = ParseIt().value(node)
                if node.nodeName == 'channelName':  newfav.episode      = ParseIt().value(node)
                if node.nodeName == 'timeslot':     newfav.timeslot     = ParseIt().value(node)
                if node.nodeName == 'firstRun':     newfav.firstRun     = True
                if node.nodeName == 'reRun':        newfav.reRun        = True
                if node.nodeName == 'quality':      newfav.quality      = ParseIt().value(node)
                if node.nodeName == 'startPadding': newfav.startPadding = ParseIt().value(node)
                if node.nodeName == 'stopPadding':  newfav.stopPadding  = ParseIt().value(node)
                if node.nodeName == 'keepAtMost':   newfav.keepAtMost   = ParseIt().value(node)
                if node.nodeName == 'autoDelete':   newfav.autoDelete   = True
            if newfav.title != '': self.favorite.append(copy.copy(newfav))
        return self.favorite

    def showsLtd(self,dom):
        self.shows = []
        for shownode in dom.getElementsByTagName('show'):
            newshow = Show()
            newshow.epgId = shownode.getAttribute('epgId')
            for node in shownode.childNodes:
                if node.nodeName == 'title':
                    newshow.title = ParseIt().value(node)
                    # Split on / or \ so we can properly keep archives listed.
                    tempTitle = SingleParse().parse(newshow.title,'(.*)/.*',0)
                    if tempTitle != "":
                        newshow.title = tempTitle
                if node.nodeName == 'episode':     newshow.episode     = ParseIt().value(node)
                if node.nodeName == 'description': newshow.description = ParseIt().value(node)

                if node.nodeName == 'airing':
                    tAiring = Airing()
                    tAiring.channelId  = node.getAttribute('channelId')
                    tAiring.favoriteId = node.getAttribute('favoriteId')
                    tAiring.duration   = node.getAttribute('duration')
                    tAiring.sageDbId   = node.getAttribute('sageDbId')
                    tAiring.startTime  = DateConv().object(node.getAttribute('startTime'))
                    newshow.startTime  = copy.copy(tAiring.startTime)
                    newshow.timestamp  = DateConv().time(tAiring.startTime)
                    newshow.datestamp  = DateConv().date(tAiring.startTime)
                    newshow.duration   = copy.copy(tAiring.duration)
                    for airnode in node.childNodes:
                        if airnode.nodeName == 'mediafile':
                            mf = MediaFile()
                            mf.sageDbId = airnode.getAttribute('sageDbId')
                            for mfnode in airnode.childNodes:
                                if mfnode.nodeName == 'archived': mf.archived = True
                                for seglist in mfnode.childNodes:
                                    if seglist.nodeName == 'segmentList':
                                        for segment in seglist.childNodes:
                                            if segment.nodeName == 'segment':
                                                seg = Segment()
                                                seg.duration  = segment.getAttribute('duration')
                                                seg.filePath  = segment.getAttribute('filePath')
                                                seg.startTime = DateConv().object(node.getAttribute('startTime'))
                                                mf.segments.append(copy.copy(seg))
                            tAiring.mediaFiles.append(copy.copy(mf))
                    newshow.airings.append(copy.copy(tAiring))
            if newshow.title != '': self.shows.append(newshow.copy())
        return self.shows

    def shows(self,dom,channels):
        self.shows = []
        for shownode in dom.getElementsByTagName('show'):
            newshow = Show()
            newshow.epgId = shownode.getAttribute('epgId')
            for node in shownode.childNodes:
                if node.nodeName == 'title':           newshow.title           = ParseIt().value(node)
                if node.nodeName == 'episode':         newshow.episode         = ParseIt().value(node)
                if node.nodeName == 'duration':        newshow.duration        = ParseIt().value(node)
                if node.nodeName == 'category':        newshow.category        = ParseIt().value(node)
                if node.nodeName == 'subCategory':     newshow.subCategory     = ParseIt().value(node)
                if node.nodeName == 'description':     newshow.description     = ParseIt().value(node)
                if node.nodeName == 'rating':          newshow.rating          = ParseIt().value(node)
                if node.nodeName == 'year':            newshow.year            = ParseIt().value(node)
                if node.nodeName == 'language':        newshow.language        = ParseIt().value(node)
                if node.nodeName == 'originalAirDate': newshow.originalAirDate = ParseIt().value(node)
                if node.nodeName == 'advisoryList':
                    for adList in node.childNodes:
                        if adList.nodeName == "advisory": newshow.advisoryList.append(ParseIt().value(adList))
                if node.nodeName == 'peopleList':
                    for pList in node.childNodes:
                        if pList.nodeName == 'person':
                            person        = People()
                            person.role   = pList.getAttribute('role')
                            person.person = ParseIt().value(pList)
                            newshow.peopleList.append(copy.copy(person))
                if node.nodeName == 'airing':
                    tAiring = Airing()
                    channelId          = node.getAttribute('channelId')
                    tAiring.favoriteId = node.getAttribute('favoriteId')
                    tAiring.duration   = node.getAttribute('duration')
                    tAiring.sageDbId   = node.getAttribute('sageDbId')
                    tAiring.startTime  = DateConv().object(node.getAttribute('startTime'))
                    for i in range(len(channels)):
                        if channels[i].channelId == channelId:
                            tAiring.channelId  = channels[i].channelNumber + " " + channels[i].channelName + " " + channels[i].channelNetwork
                    newshow.startTime  = copy.copy(tAiring.startTime)
                    newshow.timestamp  = DateConv().time(tAiring.startTime)
                    newshow.datestamp  = DateConv().date(tAiring.startTime)
                    newshow.duration   = copy.copy(tAiring.duration)
                    for airnode in node.childNodes:
                        if airnode.nodeName == 'parentalRating':  tAiring.parentalRating  = ParseIt().value(airnode)
                        if airnode.nodeName == 'premierFinale':   tAiring.premierFinale   = ParseIt().value(airnode)
                        if airnode.nodeName == 'isHDTV':          tAiring.isHDTV          = True
                        if airnode.nodeName == 'stereo':          tAiring.stereo          = True
                        if airnode.nodeName == 'subtitled':       tAiring.subtitled       = True
                        if airnode.nodeName == 'closedCaptioned': tAiring.closedCaptioned = True
                        if airnode.nodeName == 'sap':             tAiring.sap             = True
                        if airnode.nodeName == 'mediafile':
                            mf = MediaFile()
                            mf.duration  = airnode.getAttribute('duration')
                            mf.sageDbId  = airnode.getAttribute('sageDbId')
                            mf.startTime = DateConv().object(airnode.getAttribute('startTime'))
                            mf.type      = airnode.getAttribute('type')
                            for mfnode in airnode.childNodes:
                                if mfnode.nodeName == 'archived': mf.archived = True
                                if mfnode.nodeName == 'segmentList':
                                    for seglist in mfnode.childNodes:
                                        if seglist.nodeName == 'segment':
                                            seg = Segment()
                                            seg.duration  = seglist.getAttribute('duration')
                                            seg.filePath  = seglist.getAttribute('filePath')
                                            seg.startTime = DateConv().object(seglist.getAttribute('startTime'))
                                            mf.segments.append(copy.copy(seg))
                            tAiring.mediaFiles.append(copy.copy(mf))
                    newshow.airings.append(copy.copy(tAiring))
            if newshow.title != '':
                self.shows.append(newshow.copy())
        return self.shows

class AiringActions:
    def getMediaFileForAiring(self, sageDbId):
        xmldoc   = GetAsXML(webaddress+"/sagex/rpcXbmc/AiringAPI/GetMediaFileForAiring/airing:" + str(sageDbId))
        channels = ParseIt().channels(xmldoc)
        result   = ParseIt().shows(xmldoc,channels)
        xmldoc.unlink()
        return result
    def getAiringForID(self, sageDbId):
        xmldoc   = GetAsXML(webaddress+"/sagex/rpcXbmc/AiringAPI/GetAiringForID/" + str(sageDbId))
        channels = ParseIt().channels(xmldoc)
        result   = ParseIt().shows(xmldoc,channels)
        xmldoc.unlink()
        return result
    def isWatched(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/IsWatched/airing:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result
    def isDontLike(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/IsDontLike/airing:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result
    def isFavorite(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/IsFavorite/airing:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result
    def isManualRecord(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/IsManualRecord/airing:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result
    def isNotManualOrFavorite(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/IsNotManualOrFavorite/airing:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result
    def setWatched(self, sageDbId):
        dialog.ok("","Sending set watched to sagex")
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/SetWatched/airing:" + str(sageDbId))
        dialog.ok("","got the return")
        time.sleep(1)
        return True
    def clearWatched(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/ClearWatched/airing:" + str(sageDbId))
        time.sleep(1)
        return True
    def setDontLike(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/SetDontLike/airing:" + str(sageDbId))
        time.sleep(1)
        return True
    def clearDontLike(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/ClearDontLike/airing:" + str(sageDbId))
        time.sleep(1)
        return True
    def getDefaultRecordingQuality(self):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/Global/GetDefaultRecordingQuality")
        result = SingleParse().parse(WebXML,'value>(.+)<.value',0)
        return result
    def getRecordingQuality(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetRecordingQuality/airing:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(.+)<.value',0)
        if result == '': result = 'Default'
        return result
    def setRecordingQuality(self, sageDbId, quality):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/SetRecordingQuality/airing:" + str(sageDbId) + "/" + quality)
        return true
    def setRecordingTimes(self, sageDbId, start, end):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/SetRecordingTimes/airing:" + str(sageDbId) + "/" + str(start) + "/" + str(end))
        return true
    def cancelRecord(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/CancelRecord/airing:" + str(sageDbId))
        time.sleep(1)
        return False
    def setRecord(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/Record/airing:" + str(sageDbId))
        time.sleep(1)
        return False
    def getSchedStart(self, sageDbId):
        WebXML   = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetScheduleStartTime/airing:" + str(sageDbId))
        actual   = int(SingleParse().parse(WebXML,'value>(\\d+)<.value',0))
        return actual
    def getSchedEnd(self, sageDbId):
        WebXML   = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetScheduleEndTime/airing:" + str(sageDbId))
        actual   = int(SingleParse().parse(WebXML,'value>(\\d+)<.value',0))
        return actual
    def getStartPadding(self, sageDbId):
        WebXML   = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetScheduleStartTime/airing:" + str(sageDbId))
        actual   = int(SingleParse().parse(WebXML,'value>(\\d+)<.value',0))/60
        WebXML   = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetAiringStartTime/airing:" + str(sageDbId))
        original = int(SingleParse().parse(WebXML,'value>(\\d+)<.value',0))/60
        return actual-original
    def getEndPadding(self, sageDbId):
        WebXML   = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetScheduleEndTime/airing:" + str(sageDbId))
        actual   = int(SingleParse().parse(WebXML,'value>(\\d+)<.value',0))/60
        WebXML   = GetWebPage(webaddress + "/sagex/rpcXbmc/AiringAPI/GetAiringEndTime/airing:" + str(sageDbId))
        original = int(SingleParse().parse(WebXML,'value>(\\d+)<.value',0))/60
        return actual-original

class MFActions:
    def isFileCurrentlyRecording(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/MediaFileAPI/IsFileCurrentlyRecording/mediafile:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result
    def getMediaFileEncoding(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/MediaFileAPI/GetMediaFileFormatDescription/mediafile:" + str(sageDbId))
        result = SingleParse().parse(WebXML,'value>(.*)<.value',0)
        return result
    def MoveFileToLibrary(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/MediaFileAPI/MoveFileToLibrary/airing:" + str(sageDbId))
        time.sleep(1)
        return True
    def MoveTVFileOutOfLibrary(self, sageDbId):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/MediaFileAPI/MoveTVFileOutOfLibrary/airing:" + str(sageDbId))
        time.sleep(1)
        return True
    def getMediaFiles(self, length, sortby, rev):
        WebXML  = GetWebPage(webaddress + "/sagex/rpcXbmc/MediaFileAPI/GetMediaFiles/maxlen:" + str(length) + "/sortby:" + sortby + "/reverse:" + rev)
        xmldoc  = WebXMLContent(WebXML)
        result  = ParseIt().showsLtd(xmldoc)
        xmldoc.unlink()
        return result
    def delete(self, sageDbId):
        GetWebPage(webaddress + "/sagex/rpcXbmc/MediaFileAPI/Delete/mediafile:" + str(sageDbId))
        return True


class ShowActions:
    def isShowFirstRun(self, epgID):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/ShowAPI/IsShowFirstRun/show:" + str(epgID))
        result = SingleParse().parse(WebXML,'value>(\\w+)<.value',0)
        if result.lower() == "true": result = True
        else : result = False
        return result

class GlobalActions:
    def getScheduledRecordings(self, length, sortby, rev):
        WebXML = GetWebPage(webaddress + "/sagex/rpcXbmc/Global/GetScheduledRecordings/maxlen:" + str(length) + "/sortby:" + sortby + "/reverse:" + rev)
        xmldoc = WebXMLContent(WebXML)
        result = ParseIt().showsLtd(xmldoc)
        xmldoc.unlink()
        return result

class Transcode:
    def getTranscodeFormats(self):
        xmldoc = GetAsXML(webaddress + "/sagex/rpcXbmc/TranscodeAPI/GetTranscodeFormats")
        result = ParseIt().genericValues(xmldoc)
        xmldoc.unlink()
        return result
    def clearTranscodedJobs(self):
        GetWebPage(webaddress + "/sagex/rpcXbmc/TranscodeAPI/ClearTranscodedJobs")
    def getTranscodeJobs(self):
        xmldoc = GetAsXML(webaddress + "/sagex/rpcXbmc/TranscodeAPI/GetTranscodeJobs")
        result = ParseIt().genericValues(xmldoc)
        xmldoc.unlink()
        return result
    def getTranscodeJobSourceFile(self, jobID):
        xmldoc = GetAsXML(webaddress + "/sagex/rpcXbmc/TranscodeAPI/GetTranscodeJobSourceFile/" + str(jobID))
        result = ParseIt().showsLtd(xmldoc)
        xmldoc.unlink()
        return result
    def getTranscodeJobStatus(self, jobID):
        xmldoc = GetAsXML(webaddress + "/sagex/rpcXbmc/TranscodeAPI/GetTranscodeJobStatus/" + str(jobID))
        result = ParseIt().genericValue(xmldoc)
        xmldoc.unlink()
        return result

# Favorites are not handled yet in the SageAPI we use.  So we will use rpcXml instead of rpcXbmc at times when the object needs to be passed in
class FavoriteActions:
    def getObject(self, favoriteId):
        xmldoc = GetAsXML(webaddress + "/sagex/rpcXml/FavoriteAPI/GetFavoriteForID/" + str(favoriteId))
        result = ParseIt().objectRef(xmldoc)
        xmldoc.unlink()
        return str(result)
    def addFavorite(self, title, firstRuns, reRuns, category, subCategory, person, role, rated, year, parentalRating, network, channel, timeslot, keyword):
        url = webaddress + "/sagex/rpcXbmc/FavoriteAPI/AddFavorite"
        url = url + "/" + title
        url = url + "/" + firstRuns
        url = url + "/" + reRuns
        url = url + "/" + category
        url = url + "/" + subCategory
        url = url + "/" + person
        url = url + "/" + role
        url = url + "/" + rated
        url = url + "/" + year
        url = url + "/" + parentalRating
        url = url + "/" + network
        url = url + "/" + channel
        url = url + "/" + timeslot
        url = url + "/" + keyword
        GetWebPage(url)
        return True
    def getFavorite(self, favoriteID):
        WebXML  = GetWebPage(webaddress + "/sagex/rpcXbmc/FavoriteAPI/GetFavoriteForID/" + str(favoriteID))
        xmldoc  = WebXMLContent(WebXML)
        result  = ParseIt().favorites(xmldoc)
        xmldoc.unlink()
        if len(result) == 0:
            temp = Favorite()
            temp.title = "Not Set"
            result.append(temp)
        return result
    def setDontAutodelete(self, objId, autodelete):
        GetWebPage(webaddress + "/sagex/rpcXml/FavoriteAPI/SetDontAutodelete/" + objId + "/" + autodelete)
        return true
    def setFavoriteChannel(self, objId, callsign):
        if callsign == "Any":
            callsign = ""
        GetWebPage(webaddress + "/sagex/rpcXml/FavoriteAPI/SetFavoriteChannel/" + objId + "/" + callsign)
        return true
    def setFavoriteQuality(self, objId, quality):
        if quality == "Default":
            quality = ""
        GetWebPage(webaddress + "/sagex/rpcXml/FavoriteAPI/SetFavoriteQuality/" + objId + "/" + quality)
        return true
    def setKeepAtMost(self, objId, numToKeep):
        if numToKeep == "All":
            numToKeep = "0"
        GetWebPage(webaddress + "/sagex/rpcXml/FavoriteAPI/SetKeepAtMost/" + objId + "/" + numToKeep)
        return true
    def setRunStatus(self, objId, first, rerun):
        GetWebPage(webaddress + "/sagex/rpcXml/FavoriteAPI/SetRunStatus/" + objId + "/" + first + "/" + rerun)
        return true




